home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 5 / MacMania 5.toast / / Internet software / Analog 2.0 / Analog 2.0 Src / analog.c < prev    next >
C/C++ Source or Header  |  1997-02-12  |  32KB  |  1,046 lines

  1. /*** analog 2.0 ***/
  2. /* Please read Readme.html, or http://www.statslab.cam.ac.uk/~sret1/analog/  */
  3.  
  4. /*** analog.c; the main function ***/
  5.  
  6. #include "analhea2.h"
  7.  
  8. int main(int argc, char **argv)
  9. {
  10.   extern char *commandname;    /* all global vars declared in init.c */
  11.   extern struct loglist *logfilehead;
  12.   extern struct stringlist *cachefilehead, *refloghead, *browloghead;
  13.   extern struct stringlist *errloghead;
  14. #ifndef NODNS
  15.   extern char *dnsfile;
  16.   extern flag dnsq;
  17.   extern struct dnscache **dnshead;
  18.   extern size_t dnshashsize;
  19.   struct dnscache *dnsp, *dnsnextp;
  20. #endif
  21.   extern flag byq, browbyq, refbyq;
  22.   extern flag filemaskq, hostmaskq, q7, warnq, anywarns;
  23.   extern flag mq, hq, Hq, dq, Dq, Wq, sq, Sq, oq, iq, tq, rq, fq, Bq, bq, cq;
  24.   extern flag eq;
  25.   extern int osortby, rsortby, isortby, tsortby, Ssortby, fsortby;
  26.   extern int bsortby, Bsortby;
  27.   extern char bcols[], Bcols[], fcols[];
  28.   extern char mgraph, dgraph, Dgraph, hgraph, Hgraph, Wgraph;
  29.   extern char *rminreqstr, *iminreqstr, *tminreqstr, *Sminreqstr;
  30.   extern char *fminreqstr, *bminreqstr, *Bminreqstr;
  31.   extern char *rminpagestr, *iminpagestr, *tminpagestr, *Sminpagestr;
  32.   extern char *fminpagestr, *bminpagestr, *Bminpagestr;
  33.   extern char *rminbytestr, *iminbytestr, *tminbytestr, *Sminbytestr;
  34.   extern char *fminbytestr, *bminbytestr, *Bminbytestr;
  35.   extern int rmaxreqs, imaxreqs, tmaxreqs, Smaxreqs, fmaxreqs;
  36.   extern int bmaxreqs, Bmaxreqs, eminreqs;
  37.   extern int rmaxpages, imaxpages, tmaxpages, Smaxpages, fmaxpages;
  38.   extern int bmaxpages, Bmaxpages;
  39.   extern double rmaxbytes, imaxbytes, tmaxbytes, Smaxbytes, fmaxbytes;
  40.   extern double bmaxbytes, Bmaxbytes;
  41.   extern size_t rhashsize, ihashsize, thashsize, Shashsize, fhashsize;
  42.   extern size_t bhashsize, Bhashsize;
  43.   extern int Smaxlength;
  44.   extern struct timestruct firsttime, lasttime, fromtime, totime, oldtime;
  45.   extern int no_hosts, no_hosts7, no_new_hosts7;
  46.   extern int no_urls, no_urls7;
  47.   extern int cachereqs, cachereqs7, cachepages, cachepages7;
  48.   extern int corrupt_lines, other_lines;
  49.   extern double total_bytes, total_bytes7, total_ref_bytes, total_brow_bytes;
  50.   extern int total_succ_reqs, total_fail_reqs, total_other_reqs;
  51.   extern int total_succ_reqs7, total_fail_reqs7, total_other_reqs7;
  52.   extern int total_page_reqs, total_page_reqs7;
  53.   extern int total_good_refs, total_bad_refs, total_masked_refs;
  54.   extern int total_good_brows, total_bad_brows, total_masked_brows;
  55.   extern int total_ref_pages, total_brow_pages;
  56.   extern struct weekly *firstW;
  57.   extern struct genstruct **Shead, **rhead, **ihead, **thead, **fhead;
  58.   extern struct genstruct **bhead, **Bhead, **Shead2, **rhead2, **fhead2;
  59.   extern int errors[];
  60.   extern int onumber;
  61.   extern struct include *wanthosthead, *wantreqhead;
  62.   extern int debug, progressfreq;
  63.   extern int status[], status7[], statusnos[];
  64.  
  65.   FILE *lf;
  66.   flag ispipe;           /* whether the currently open logfile is a pipe */
  67.   struct loglist *logfilep;
  68.   struct stringlist *otherlogp;
  69.   char inputline[MAXLINELENGTH];  /* a particular input line */
  70.   int linetype;          /* COMMON, NCSAOLD, WEBSTAR or CORRUPT */
  71.   char hostn[MAXSTRINGLENGTH];
  72.   int date, year, hr, min, monthno;
  73.   long thistimecode;
  74.   char fromurl[MAXSTRINGLENGTH];
  75.   char browser[MAXSTRINGLENGTH];
  76.   char errstr[MAXLINELENGTH];
  77.   char filename[MAXSTRINGLENGTH];
  78.   int code;
  79.   size_t preflength;     /* length of filename prefix for this logfile */
  80.   flag firstreq = TRUE;
  81.   flag datemaskq;
  82.   flag fwarn1 = OFF, fwarn2 = OFF, fwarn3 = OFF;
  83.   flag bwarn1 = OFF, bwarn2 = OFF, bwarn3 = OFF, bwarn4 = OFF;
  84.   /* have certain warnings been given? */
  85.   double bytes;    /* long is not big enough; double has more sig. figs,
  86.               and copes with overflow automatically. */
  87.   char bytestr[16];
  88.  
  89.   struct genstruct *rsorthead, *isorthead, *tsorthead, *Ssorthead;
  90.   struct genstruct *fsorthead, *bsorthead, *Bsorthead;
  91.   int firstdom, errorder[NO_ERRS];     /* heads for sorting */
  92.  
  93.   struct genstruct *hostp, *hostnextp, *urlp, *urlnextp;
  94.   int onlist;
  95.  
  96.   flag wantthisone = TRUE;  /* whether we want to analyse a particular entry */
  97.   flag issuccess;           /* whether an entry has a success status code */
  98.   flag ispage = OFF;        /* whether it represents a page */
  99.   flag last7q = OFF;        /* are we now in the last 7 days? */
  100.   int rc;
  101.   register int linesread;
  102.   int nextreport;
  103.   char *tempstr, *tempc;
  104.   int i, tempint, tempint2;
  105.   flag tempf;
  106.   char tempchar, tempchar2;
  107.   struct genstruct *tempgs;
  108.  
  109.   /*** Initialisation ***/
  110.  
  111. #ifdef MAC_EVENTS
  112.   MacInit();
  113. #endif
  114.   initialise(argc, argv);
  115.   linesread = 0;
  116.   nextreport = progressfreq;
  117.   datemaskq = (fromtime.code > -INFINITY || totime.code < INFINITY);
  118.  
  119.   /*** Now start scanning ***/
  120.  
  121.   for (logfilep = logfilehead; logfilep -> name[0] != '\0';
  122.        logfilep = logfilep -> next) {  /* for each logfile */
  123.  
  124.     lf = fopenlog(logfilep -> name, "logfile", &ispipe);
  125.     if (lf != NULL) {
  126.  
  127.       preflength = strlen(logfilep -> prefix);
  128.  
  129.       while(fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  130.  
  131.     strcpy(filename, logfilep -> prefix);
  132.     /* needed each line coz can get accidentally overwritten by /../ */
  133.  
  134.     linetype = CORRUPT;   /* paranoia :) */
  135.  
  136.     if ((rc = sscanf_common(inputline, hostn, &date, &monthno, &year, &hr,
  137.                 &min, filename + preflength, fromurl, browser,
  138.                 &code, bytestr, preflength)) >= 9) {
  139.       linetype = COMMON;
  140.       bytes = atof(bytestr);
  141.     }
  142. #ifdef WEBSTAR
  143.     else if ((rc = sscanf_webstar(inputline, hostn, &date, &monthno, &year,
  144.                       &hr, &min, filename + preflength,
  145.                       fromurl, browser, &code, bytestr,
  146.                       preflength)) >= 9) {
  147.       linetype = WEBSTARLINE;
  148.       bytes = atof(bytestr);
  149.     }
  150. #endif
  151. #ifdef NETPRESENZ
  152.     else if ((rc = sscanf_netpresenz(lf, inputline, hostn, &date, &monthno,
  153.                      &year, &hr, &min,
  154.                      filename + preflength, fromurl,
  155.                      browser, &code, bytestr,
  156.                      preflength)) >= 9) {
  157.       linetype = NETPRESENZLINE;
  158.       bytes = 0;
  159.       if (byq) {
  160.         fprintf(stderr, "%s: Warning: Netpresenz logs contain no bytes information:\n", commandname);
  161.         fprintf(stderr, "  will not report on bytes transferred.\n");
  162.         byq = OFF;
  163.         if (osortby == BYBYTES)
  164.           osortby = BYREQUESTS;
  165.         if (rsortby == BYBYTES)
  166.           rsortby = BYREQUESTS;
  167.         if (isortby == BYBYTES)
  168.           isortby = BYREQUESTS;
  169.         if (tsortby == BYBYTES)
  170.           tsortby = BYREQUESTS;
  171.         if (Ssortby == BYBYTES)
  172.           Ssortby = BYREQUESTS;
  173.         if (mgraph == 'b' || mgraph == 'B')
  174.           mgraph = 'r';
  175.         if (dgraph == 'b' || dgraph == 'B')
  176.           dgraph = 'r';
  177.         if (Dgraph == 'b' || Dgraph == 'B')
  178.           Dgraph = 'r';
  179.         if (hgraph == 'b' || hgraph == 'B')
  180.           hgraph = 'r';
  181.         if (Hgraph == 'b' || Hgraph == 'B')
  182.           Hgraph = 'r';
  183.         if (Wgraph == 'b' || Wgraph == 'B')
  184.           Wgraph = 'r';
  185.       }
  186.     }
  187. #endif
  188.     else if ((rc = sscanf_ncsaold(inputline, hostn, &monthno, &date, &hr,
  189.                       &min, &year, filename + preflength,
  190.                       preflength)) == 7) {
  191.       linetype = NCSAOLD;
  192.       code = 200;
  193.       bytes = 0;
  194.       if (byq) {
  195.         fprintf(stderr, "%s: Warning: old style NCSA logs contain no bytes information:\n", commandname);
  196.         fprintf(stderr, "  will not report on bytes transferred.");
  197.         byq = OFF;
  198.         if (osortby == BYBYTES)
  199.           osortby = BYREQUESTS;
  200.         if (rsortby == BYBYTES)
  201.           rsortby = BYREQUESTS;
  202.         if (isortby == BYBYTES)
  203.           isortby = BYREQUESTS;
  204.         if (tsortby == BYBYTES)
  205.           tsortby = BYREQUESTS;
  206.         if (Ssortby == BYBYTES)
  207.           Ssortby = BYREQUESTS;
  208.         if (mgraph == 'b' || mgraph == 'B')
  209.           mgraph = 'r';
  210.         if (dgraph == 'b' || dgraph == 'B')
  211.           dgraph = 'r';
  212.         if (Dgraph == 'b' || Dgraph == 'B')
  213.           Dgraph = 'r';
  214.         if (hgraph == 'b' || hgraph == 'B')
  215.           hgraph = 'r';
  216.         if (Hgraph == 'b' || Hgraph == 'B')
  217.           Hgraph = 'r';
  218.         if (Wgraph == 'b' || Wgraph == 'B')
  219.           Wgraph = 'r';
  220.       }
  221.     }
  222.       
  223.     if (linetype != CORRUPT) {
  224.     
  225.       thistimecode = timecode(date, monthno, year, hr, min);
  226.       wantthisone = thistimecode >= fromtime.code &&
  227.         thistimecode <= totime.code;
  228.       if (wantthisone && hostmaskq) {  /* must hostmask before req. hash */
  229.         doaliashost(hostn);
  230.         wantthisone = included(hostn, UNSET, wanthosthead);
  231.       }
  232.       if (wantthisone) {
  233.         issuccess = (code <= 299 || code == 304);
  234.         /* Are we in the last 7 days? Check this every time in case */
  235.         /* logfile is not in chronological order */
  236.         if (q7)   /* if !q7, last7q stays off (for efficiency) */
  237.           last7q = (thistimecode > oldtime.code);
  238.     
  239.         /* Request report. We always construct a (poss. silent) request
  240.            report in order to generate ispage etc. */
  241.         tempgs = hashadd(rhead2, rhashsize, filename, issuccess,
  242.                  issuccess?bytes:0, UNSET,
  243.                  last7q, &tempint, &tempint, &tempint,
  244.                  OFF, filemaskq, UNSET,
  245.                  (struct genstruct *)NULL, -1, 'r');
  246.         wantthisone = tempgs -> wanted;
  247.         ispage = tempgs -> ispage;
  248.       }
  249.       if (wantthisone) {
  250.         /* Hostname report/count. This time, we don't do one if the
  251.            domain report or hostmaskq is on and this is off, because
  252.            this takes up a lot of memory. */
  253.         if (sq == ON) {
  254.           if (hostmaskq)  /* then aliasing already done */
  255.         hashadd(Shead2, Shashsize, hostn, issuccess, issuccess?bytes:0,
  256.             issuccess && ispage, last7q, &tempint, &tempint,
  257.             &tempint, ON, OFF, OFF, (struct genstruct *)NULL,
  258.             -1, 'S');  /* and we know it's wanted */
  259.           else
  260.         wantthisone = hashadd(Shead2, Shashsize, hostn, issuccess,
  261.                       issuccess?bytes:0, issuccess && ispage,
  262.                       last7q, &tempint, &tempint, &tempint,
  263.                       OFF, OFF, OFF, (struct genstruct *)NULL,
  264.                       -1, 'S') -> wanted;
  265.         }
  266.         else if (issuccess) {
  267.           if (!hostmaskq && (oq || sq == APPROX)) {
  268.         doaliashost(hostn);
  269.         wantthisone = included(hostn, UNSET, wanthosthead);
  270.           }
  271.           if /* still */ (wantthisone) {
  272.         if (oq)
  273.           domhashadd(hostn, 1, ispage, bytes);
  274.         if (sq == APPROX)
  275.           approxhosthashadd(hostn, last7q);
  276.           }
  277.         }
  278.       }
  279.  
  280.       if (!wantthisone)
  281.         ++other_lines;
  282.       else {
  283.         /* add to the right status code total */
  284.         tempf = OFF;
  285.         for (i = 0; !tempf && i < NO_STATUS; i++) {
  286.           if (code <= statusnos[i]) {
  287.         status[i]++;
  288.         if (last7q)
  289.           status7[i]++;
  290.         tempf = ON;
  291.           }
  292.         }
  293.  
  294.         if (issuccess) {
  295.           if (ispage) {
  296.         total_page_reqs++;
  297.         total_page_reqs7 += last7q;
  298.           }
  299.           total_bytes += bytes;  /* NB only count bytes for successes */
  300.           if (last7q)
  301.         total_bytes7 += bytes;
  302.  
  303.           if (firstreq) {
  304.         firstreq = FALSE;
  305.         firsttime.date = date;
  306.         firsttime.monthno = monthno;
  307.         firsttime.year = year;
  308.         firsttime.hr = hr;
  309.         firsttime.min = min;
  310.         firsttime.code = thistimecode;
  311.         if (Wq)
  312.           firstW -> start = startofweek(firsttime);
  313.         lasttime.date = date;
  314.         lasttime.monthno = monthno;
  315.         lasttime.year = year;
  316.         lasttime.hr = hr;
  317.         lasttime.min = min;
  318.         lasttime.code = thistimecode;
  319.           }
  320.       
  321.           /* date cataloguing */
  322.  
  323.           datehash(year, monthno, date, hr, min, thistimecode, 1, ispage,
  324.                bytes);
  325.  
  326.         }    /* end if issuccess */
  327.     
  328.         if (rc == 11) {  /* then do referrer and browser now (all codes) */
  329.           if (fq && fromurl[0] != '\0')
  330.         addref(fromurl, filename, ispage, bytes, last7q, OFF);
  331.           if ((Bq || bq) && browser[0] != '\0')
  332.         addbrowser(browser, ispage, bytes, last7q);
  333.         }
  334.  
  335.       }  /* end if want this one */
  336.       
  337.     }   /* end if linetype != CORRUPT */
  338.  
  339.     else {   /* line is corrupt */
  340.       ++corrupt_lines;
  341.       if (debug != 0)
  342.         fprintf(stderr, "C: %s", inputline);
  343.       if (strchr(inputline, '\n') == NULL) {
  344.         /* line corrupt by being too long; */
  345.         fscanf(lf, "%*[^\n]");              /* read to end of line */
  346.         if (debug != 0)
  347.           fprintf(stderr, "\n");
  348.       }
  349.     }
  350.   
  351.     if ((++linesread) == nextreport) {
  352.       fprintf(stderr, "%s: %d lines read\n", commandname, linesread);
  353.       nextreport += progressfreq;
  354.     }
  355.  
  356. #ifdef MAC_EVENTS
  357.     if ((linesread % MAC_IDLE_FREQ) == 0)
  358.       MacIdle();
  359. #endif
  360.  
  361.       }   /* end of reading this logfile */
  362.  
  363.       fcloselog(lf, logfilep -> name, "logfile", ispipe);
  364.  
  365.     }
  366.   }    /*** End of main loop (for all logfiles) ***/
  367.  
  368.   /*** Now for the other logfiles. First cache files. ***/
  369.   /* NB Some of this is shared with main loop and could probably be combined */
  370.  
  371.   min = 30;   /* reckon all cache entries at half past the hour */
  372.   for (otherlogp = cachefilehead; otherlogp -> name[0] != '\0';
  373.        otherlogp = otherlogp -> next) {  /* for each referrer log */
  374.     
  375.     lf = fopenlog(otherlogp -> name, "cache file", &ispipe);
  376.     if (lf != NULL) {
  377.  
  378.       if (fgets(inputline, MAXLINELENGTH, lf) == NULL ||
  379.       sscanf(inputline, "CACHE type %c produced by analo%c", &tempchar,
  380.          &tempchar2) != 2 ||
  381.       tempchar2 != 'g' || (tempchar != '1' && tempchar != '2')) {
  382.     if (warnq) {
  383.       fprintf(stderr, "%s: Warning: %s appears not to be a cache file: ignoring it\n", commandname, otherlogp -> name);
  384.       anywarns = ON;
  385.     }
  386.       }
  387.       else {
  388.     if (tempchar == '1') {
  389.       tempint2 = 0;  /* number of page requests then always zero */
  390.       if (warnq) {
  391.         fprintf(stderr, "%s: Warning: old style cache file %s contains no page information:\n",
  392.             commandname, otherlogp -> name);
  393.         fprintf(stderr, "  page counts will be too low\n");
  394.         anywarns = ON;
  395.       }
  396.     }
  397.     while (fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  398.       if ((tempstr = strtok(inputline, ":")) != NULL) {
  399.         tempc = tempstr;
  400.         if (strlen(tempstr) != 10) {
  401.           if (warnq) {
  402.         fprintf(stderr, "%s: Warning: ignoring corrupt line in cache file %s starting %s\n", commandname, otherlogp -> name, tempc);
  403.         anywarns = ON;
  404.           }
  405.         }
  406.         else {
  407.           year = 1000 * (*tempstr - '0');
  408.           year += 100 * (*(++tempstr) - '0');
  409.           year += 10 * (*(++tempstr) - '0');
  410.           year += (*(++tempstr) - '0');
  411.           monthno = 10 * (*(++tempstr) - '0');
  412.           monthno += *(++tempstr) - '0' - 1;
  413.           date = 10 * (*(++tempstr) - '0');
  414.           date += *(++tempstr) - '0';
  415.           hr = 10 * (*(++tempstr) - '0');
  416.           hr += *(++tempstr) - '0';
  417.           tempf = OFF;
  418.           for ( ; hr < 24 && !tempf; hr++) {
  419.         if ((tempstr = strtok((char *)NULL, ":")) == NULL) {
  420.           if (warnq) {
  421.             fprintf(stderr, "%s: Warning: missing data in cache file %s at line starting %s\n", commandname, otherlogp -> name, tempc);
  422.             anywarns = ON;
  423.           }
  424.           tempf = ON;
  425.         }
  426.         else if (tempstr[0] == '*')
  427.           tempf = ON;
  428.         else {
  429.           tempint = atoi(tempstr);
  430.           if (tempchar == '2') {
  431.             if ((tempstr = strtok((char *)NULL, ":")) == NULL) {
  432.               if (warnq) {
  433.             fprintf(stderr, "%s: Warning: missing data in cache file %s at line starting %s\n", commandname, otherlogp -> name, tempc);
  434.             anywarns = ON;
  435.               }
  436.               tempf = ON;
  437.             }
  438.             else
  439.               tempint2 = atoi(tempstr);
  440.           }
  441.           if ((tempstr = strtok((char *)NULL, ":")) == NULL) {
  442.             if (warnq) {
  443.               fprintf(stderr, "%s: Warning: missing data in cache file %s at line starting %s\n", commandname, otherlogp -> name, tempc);
  444.               anywarns = ON;
  445.             }
  446.             tempf = ON;
  447.           }
  448.           else {
  449.             bytes = atof(tempstr);
  450.             thistimecode = timecode(date, monthno, year, hr, min);
  451.             if (thistimecode >= fromtime.code &&
  452.             thistimecode <= totime.code) {
  453.               if (firstreq) {
  454.             firstreq = FALSE;
  455.             firsttime.date = date;
  456.             firsttime.monthno = monthno;
  457.             firsttime.year = year;
  458.             firsttime.hr = hr;
  459.             firsttime.min = min;
  460.             firsttime.code = thistimecode;
  461.             if (Wq)
  462.               firstW -> start = startofweek(firsttime);
  463.             lasttime.date = date;
  464.             lasttime.monthno = monthno;
  465.             lasttime.year = year;
  466.             lasttime.hr = hr;
  467.             lasttime.min = min;
  468.             lasttime.code = thistimecode;
  469.               }
  470.               if (q7)
  471.             last7q = (thistimecode > oldtime.code);
  472.               total_bytes += bytes;
  473.               cachereqs += tempint;
  474.               cachepages += tempint2;
  475.               if (last7q) {
  476.             total_bytes7 += bytes;
  477.             cachereqs7 += tempint;
  478.             cachepages7 += tempint2;
  479.               }
  480.               datehash(year, monthno, date, hr, min, thistimecode,
  481.                    tempint, tempint2, bytes);
  482.             }
  483.           }
  484.         }
  485.           }
  486.         }
  487.       }
  488.     }
  489.       }
  490.       fcloselog(lf, otherlogp -> name, "cache file", ispipe);
  491.     }
  492.   }
  493.  
  494.   /*** Now the referrer logs ***/
  495.  
  496.   if (fq) {
  497.  
  498.     for (otherlogp = refloghead; otherlogp -> name[0] != '\0';
  499.      otherlogp = otherlogp -> next) {  /* for each referrer log */
  500.  
  501.       lf = fopenlog(otherlogp -> name, "referrer log", &ispipe);
  502.       if (lf != NULL) {
  503.  
  504.     while(fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  505.       if (sscanf_referrer(inputline, &date, &monthno, &year, &hr, &min,
  506.                  fromurl, filename) == 7) {
  507.         wantthisone = ON;
  508.         last7q = OFF;
  509.         if (datemaskq) {
  510.           if (date != 0) {
  511.         thistimecode = timecode(date, monthno, year, hr, min);
  512.         wantthisone = thistimecode > fromtime.code &&
  513.           thistimecode < totime.code;
  514.         if (q7)
  515.           last7q = (thistimecode > oldtime.code);
  516.           }
  517.           else if (!fwarn1 && warnq) {
  518.         fprintf(stderr, "%s: Warning: Referrer log contains lines with no date information;\n", commandname);
  519.         fprintf(stderr, "  cannot apply FROM and TO commands to them.\n");
  520.         fwarn1 = ON;
  521.         anywarns = ON;
  522.           }
  523.         }
  524.         if (!fwarn2 && hostmaskq && wantthisone && warnq) {
  525.           fprintf(stderr, "%s: Warning: Referrer logs contain no host information;\n", commandname);
  526.           fprintf(stderr, "  cannot apply HOSTINCLUDE and HOSTEXCLUDE commands to it.\n");
  527.           fwarn2 = ON;
  528.           anywarns = ON;
  529.         }
  530.         if (!fwarn3) {
  531.           fwarn3 = ON;
  532.           for (tempc = fcols; *tempc != '\0' && *tempc != 'B' &&
  533.            *tempc != 'b'; tempc++)
  534.         ;
  535.           if (*tempc != '\0' || fsortby == BYBYTES) {
  536.         if (warnq) {
  537.           fprintf(stderr, "%s: Warning: Referrer logs contain no bytes information;\n", commandname);
  538.           fprintf(stderr, "  cannot report on referrer bytes.\n");
  539.           anywarns = ON;
  540.         }
  541.         if (fsortby == BYBYTES)
  542.           fsortby = BYREQUESTS;
  543.         refbyq = OFF;
  544.           }
  545.         }
  546.         if (wantthisone)
  547.           addref(fromurl, filename, UNSET, 0.0, last7q, filemaskq);
  548.         else
  549.           ++total_masked_refs;
  550.       }
  551.       else
  552.         ++total_bad_refs;
  553.  
  554.     if ((++linesread) == nextreport) {
  555.       fprintf(stderr, "%s: %d lines read\n", commandname, linesread);
  556.       nextreport += progressfreq;
  557.     }
  558.  
  559. #ifdef MAC_EVENTS
  560.     if ((linesread % MAC_IDLE_FREQ) == 0)
  561.       MacIdle();
  562. #endif
  563.  
  564.     }
  565.     
  566.     fcloselog(lf, otherlogp -> name, "referrer log", ispipe);
  567.       }
  568.     }
  569.   }
  570.  
  571.   /* Next the browser logs */
  572.  
  573.   if (bq || Bq) {
  574.  
  575.     for (otherlogp = browloghead; otherlogp -> name[0] != '\0';
  576.      otherlogp = otherlogp -> next) { 
  577.  
  578.       lf = fopenlog(otherlogp -> name, "browser log", &ispipe);
  579.       if (lf != NULL) {
  580.  
  581.     while(fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  582.     
  583.       /* read in the date, if supplied */
  584.       if (*(tempstr = inputline) == '[') {
  585.         wantthisone = FALSE;  /* unless date is valid */
  586.         if (sscanf_date(++tempstr, &date, &monthno, &year, &hr, &min) ==
  587.         5) {
  588.           tempstr += 20;
  589.           if (*tempstr == ']') {
  590.         if (*(++tempstr) == ' ') {
  591.           tempstr++;
  592.           wantthisone = TRUE;
  593.         }
  594.           }
  595.         }
  596.       }
  597.       else {
  598.         wantthisone = TRUE;
  599.         date = 0;   /* as marker */
  600.       }
  601.  
  602.       if (wantthisone) {
  603.         last7q = OFF;
  604.         if (datemaskq) {
  605.           if (date != 0) {
  606.         thistimecode = timecode(date, monthno, year, hr, min);
  607.         wantthisone = thistimecode > fromtime.code &&
  608.           thistimecode < totime.code;
  609.         if (q7)
  610.           last7q = (thistimecode > oldtime.code);
  611.           }
  612.           else if (!bwarn1 && warnq) {
  613.         fprintf(stderr, "%s: Warning: Browser log contains lines with no date information;\n", commandname);
  614.         fprintf(stderr, "  cannot apply FROM and TO commands to them.\n");
  615.         bwarn1 = ON;
  616.         anywarns = ON;
  617.           }
  618.         }
  619.         if (warnq) {  /* some boring warnings */
  620.           if (!bwarn2 && hostmaskq && wantthisone) {
  621.         fprintf(stderr, "%s: Warning: Browser logs contain no host information;\n", commandname);
  622.         fprintf(stderr, "  cannot apply HOSTINCLUDE and HOSTEXCLUDE commands to them.\n");
  623.         bwarn2 = ON;
  624.         anywarns = ON;
  625.           }
  626.           if (!bwarn3 && filemaskq && wantthisone) {
  627.         fprintf(stderr, "%s: Warning: Browser logs contain no file information;\n", commandname);
  628.         fprintf(stderr, "  cannot apply FILEINCLUDE and FILEEXCLUDE commands to them.\n");
  629.         bwarn3 = ON;
  630.         anywarns = ON;
  631.           }
  632.         }
  633.         if (!bwarn4) {
  634.           bwarn4 = ON;
  635.           tempf = OFF;
  636.           if (bq && (bsortby == BYBYTES || bsortby == BYPAGES))
  637.         tempf = ON;
  638.           else if (Bq && (bsortby == BYBYTES || bsortby == BYPAGES))
  639.         tempf = ON;
  640.           else if (bq) {
  641.         for (tempc = bcols; *tempc != '\0' && *tempc != 'p' &&
  642.              *tempc != 'P' && *tempc != 'B' && *tempc != 'b';
  643.              tempc++)
  644.           ;
  645.         if (*tempc != '\0')
  646.           tempf = ON;
  647.           }
  648.           if (!tempf && Bq) {
  649.         for (tempc = Bcols; *tempc != '\0' && *tempc != 'p' &&
  650.              *tempc != 'P' && *tempc != 'B' && *tempc != 'b';
  651.              tempc++)
  652.           ;
  653.         if (*tempc != '\0')
  654.           tempf = ON;
  655.           }
  656.           if (tempf) {
  657.         if (warnq) {
  658.           fprintf(stderr, "%s: Warning: Browser logs contain no file information;\n", commandname);
  659.           fprintf(stderr, "  cannot report on browser page counts or bytes.\n");
  660.           anywarns = ON;
  661.         }
  662.         browbyq = OFF;
  663.         if (bsortby == BYBYTES || bsortby == BYPAGES)
  664.           bsortby = BYREQUESTS;
  665.         if (Bsortby == BYBYTES || Bsortby == BYPAGES)
  666.           Bsortby = BYREQUESTS;
  667.           }
  668.         }
  669.         if (wantthisone) {
  670.           if ((tempc = strchr(tempstr, '\n')) != NULL)
  671.         *tempc = '\0';
  672.           strcpy(browser, tempstr);
  673.           addbrowser(browser, OFF, 0.0, last7q);
  674.         }
  675.         else   /* masked out */
  676.           ++total_masked_brows;
  677.  
  678.       }
  679.       else    /* had bad date */
  680.         ++total_bad_brows;
  681.  
  682.       if ((++linesread) == nextreport) {
  683.         fprintf(stderr, "%s: %d lines read\n", commandname, linesread);
  684.         nextreport += progressfreq;
  685.       }
  686.  
  687. #ifdef MAC_EVENTS
  688.       if ((linesread % MAC_IDLE_FREQ) == 0)
  689.         MacIdle();
  690. #endif
  691.  
  692.     }
  693.  
  694.     fcloselog(lf, otherlogp -> name, "browser log", ispipe);
  695.  
  696.       }
  697.     }
  698.   }
  699.  
  700.   /* Finally the error logs */
  701.  
  702.   if (eq) {
  703.  
  704.     for (otherlogp = errloghead; otherlogp -> name[0] != '\0';
  705.      otherlogp = otherlogp -> next) {  /* for each logfile */
  706.  
  707.       lf = fopenlog(otherlogp -> name, "error log", &ispipe);
  708.       if (lf != NULL) {
  709.  
  710.     while(fgets(inputline, MAXLINELENGTH, lf) != NULL) {
  711.     
  712.       tempstr = inputline;
  713.  
  714.       wantthisone = FALSE;
  715.       if (*tempstr == '[') {   /* others are non-httpd errors */
  716.         if (sscanf_olddate(++tempstr, &date, &monthno, &year, &hr, &min)
  717.         == 5) {
  718.           tempstr += 24;
  719.           if (*tempstr == ']') {
  720.         if (*(++tempstr) == ' ') {
  721.           tempstr++;
  722.           wantthisone = TRUE;
  723.         }
  724.           }
  725.         }
  726.       }
  727.  
  728.       if (wantthisone) {
  729.         if (datemaskq) {
  730.           thistimecode = timecode(date, monthno, year, hr, min);
  731.           wantthisone = (thistimecode > fromtime.code) &&
  732.         (thistimecode < totime.code);
  733.         }
  734.         if (wantthisone) {
  735.           strcpy(errstr, tempstr);
  736.           adderr(errstr);
  737.         }
  738.       }
  739.  
  740.       if ((++linesread) == nextreport) {
  741.         fprintf(stderr, "%s: %d lines read\n", commandname, linesread);
  742.         nextreport += progressfreq;
  743.       }
  744.  
  745. #ifdef MAC_EVENTS
  746.       if ((linesread % MAC_IDLE_FREQ) == 0)
  747.         MacIdle();
  748. #endif
  749.  
  750.     }
  751.  
  752.     fcloselog(lf, otherlogp -> name, "error log", ispipe);
  753.       }
  754.  
  755.     }
  756.   }
  757.  
  758.   /* Now writing out the DNS cache */
  759.  
  760. #ifndef NODNS
  761.   if (dnsq) {
  762.     if (STREQ(dnsfile, "-") || STREQ(dnsfile, "stdin")) {
  763.       lf = stdout;
  764.       if (debug > 0)
  765.     fprintf(stderr, "F: Opening stdout as DNS cache output file\n");
  766.     }
  767.     else if ((lf = fopen(dnsfile, "w")) == NULL) {
  768.       if (warnq) {
  769.     fprintf(stderr,
  770.         "%s: Warning: failed to open DNS cache file %s for writing.\n",
  771.         commandname, dnsfile);
  772.     anywarns = ON;
  773.       }
  774.     }
  775.     else if (debug > 0)
  776.       fprintf(stderr, "F: Opening %s as DNS cache output file\n", dnsfile);
  777.     if (lf != NULL) {
  778.       onlist = 0;
  779.       for (dnsp = dnshead[0]; onlist < dnshashsize; dnsp = dnsnextp) {
  780.                                     /* run through hosts, as below */
  781.     if (dnsp -> number == NULL) {
  782.       dnsnextp = dnshead[++onlist];
  783.     }
  784.     else {
  785.       if (isnumeric(dnsp -> number))
  786.         fprintf(lf, "%d %s %s\n", dnsp -> altimecode, dnsp -> number,
  787.                 (dnsp -> alias == NULL)?"*":(dnsp -> alias));
  788.       dnsnextp = dnsp -> next;
  789.     }
  790.       }
  791.       fclose(lf);
  792.       if (debug > 0)
  793.     fprintf(stderr, "F: Closing %s\n",
  794.         (STREQ(dnsfile, "-") || STREQ(dnsfile, "stdin"))?"stdout":
  795.         dnsfile);
  796.     }
  797.   }
  798. #endif
  799.  
  800.   /* now start final accounting */
  801.  
  802.   for (i = 0; i < NO_STATUS; i++) {
  803.     if (statusnos[i] <= 299 || statusnos[i] == 304) {
  804.       total_succ_reqs += status[i];
  805.       total_succ_reqs7 += status7[i];
  806.     }
  807.     else if (statusnos[i] <= 399) {
  808.       total_other_reqs += status[i];
  809.       total_other_reqs7 += status7[i];
  810.     }
  811.     else {
  812.       total_fail_reqs += status[i];
  813.       total_fail_reqs7 += status7[i];
  814.     }
  815.   }
  816.  
  817.   tempint = total_succ_reqs;
  818.   total_succ_reqs += cachereqs;
  819.   total_succ_reqs7 += cachereqs7;
  820.   total_page_reqs += cachepages;
  821.   total_page_reqs7 += cachepages7;
  822.  
  823.   if (tempint == 0) {      /* no logfile successes */
  824.     if (cachereqs == 0) {  /* no cached successes either */
  825.       mq = OFF;
  826.       dq = OFF;
  827.       Dq = OFF;
  828.       Wq = OFF;
  829.       hq = OFF;
  830.       Hq = OFF;
  831.       q7 = OFF;
  832.     }
  833.     oq = OFF;
  834.     iq = OFF;
  835.     tq = OFF;
  836.     rq = OFF;
  837.     Sq = OFF;
  838.     cq = OFF;
  839.   }
  840.  
  841.   else {   /* there are things to report from the main logfile */
  842.  
  843.     if (total_succ_reqs7 == 0)
  844.       q7 = OFF;   /* just total_bytes no good in case (!byq) */
  845.  
  846.     /* Next do aliasing of hosts */
  847.  
  848.     if (sq == ON)
  849.       allaliases(Shead2, Shead, Shashsize, &no_hosts, &no_hosts7,
  850.          &no_new_hosts7, 'S');
  851.  
  852.     /* Now the domain report. This is now easy because all the hostnames
  853.        are already aliased etc. */
  854.  
  855.     if (oq && sq == ON) {
  856.       onlist = 0;                          /* the list of files we are on */
  857.       hostp = Shead[0];                    /* starting at list 0 */
  858.       for ( ; onlist < Shashsize; hostp = hostnextp) {
  859.                                            /* run through hosts */
  860.     if (hostp -> name == NULL) {       /* then finished this list */
  861.       hostnextp = Shead[++onlist];     /* so start the next list */
  862.     }
  863.     else {
  864.       strcpy(hostn, hostp -> name);
  865.       domhashadd(hostn, hostp -> reqs, hostp -> pages, hostp -> bytes);
  866.       hostnextp = hostp -> next;
  867.     }
  868.       }
  869.     }
  870.  
  871.     /* Now for aliasing filenames. */
  872.  
  873.     if (rq || iq || tq)
  874.       allaliases(rhead2, rhead, rhashsize, &no_urls, &no_urls7, &tempint,
  875.          'r');
  876.  
  877.     /* Now the filetype report */
  878.  
  879.     if (tq) {
  880.       onlist = 0;
  881.       urlp = rhead[0];
  882.       for ( ; onlist < rhashsize; urlp = urlnextp) {
  883.                                          /* run through files */
  884.     if (urlp -> name == NULL) {      /* then finished this list */
  885.       urlnextp = rhead[++onlist];    /* so start the next list */
  886.     }
  887.     else {
  888.       hashadd(thead, thashsize, urltoext(urlp -> name), urlp -> reqs,
  889.           urlp -> bytes, urlp -> pages, urlp -> last7, &tempint,
  890.           &tempint, &tempint, ON, OFF, OFF, (struct genstruct *)NULL,
  891.           -1, 't');
  892.       urlnextp = urlp -> next;
  893.     }
  894.       }
  895.     }      
  896.  
  897.     /* Now the directory report. */
  898.  
  899.     if (iq) {
  900.       onlist = 0;                        /* the list of files we are on */
  901.       urlp = rhead[0];                   /* starting at list 0 */
  902.       for ( ; onlist < rhashsize; urlp = urlnextp) {
  903.                                          /* run through files */
  904.     if (urlp -> name == NULL) {      /* then finished this list */
  905.       urlnextp = rhead[++onlist];  /* so start the next list */
  906.     }
  907.     else {
  908.       strcpy(filename, urlp -> name);
  909.       urltodir(filename);
  910.       hashadd(ihead, ihashsize, filename, urlp -> reqs, urlp -> bytes,
  911.           urlp -> pages, urlp -> last7, &tempint, &tempint, &tempint,
  912.           ON, OFF, OFF, (struct genstruct *)NULL, -1, 'i');
  913.       urlnextp = urlp -> next;
  914.     }
  915.       }
  916.     }
  917.       
  918.     /*** now for the checking and sorting ***/
  919.     
  920.     if (rq) {
  921.       rsorthead = gensort(rhead, rhashsize, total_succ_reqs,
  922.               total_page_reqs, total_bytes, rsortby, rminreqstr,
  923.               rminpagestr, rminbytestr, wantreqhead,
  924.               OFF, &rmaxreqs, &rmaxpages, &rmaxbytes, &tempint);
  925.       if (rsorthead -> name == NULL)
  926.     rq = OFF;
  927.     }
  928.  
  929.     if (iq) {
  930.       isorthead = gensort(ihead, ihashsize, total_succ_reqs,
  931.               total_page_reqs, total_bytes, isortby, iminreqstr,
  932.               iminpagestr, iminbytestr, (struct include *)NULL,
  933.               OFF, &imaxreqs, &imaxpages, &imaxbytes, &tempint);
  934.       if (isorthead -> name == NULL)
  935.     iq = OFF;
  936.     }
  937.  
  938.     if (tq) {
  939.       tsorthead = gensort(thead, thashsize, total_succ_reqs,
  940.               total_page_reqs, total_bytes, tsortby, tminreqstr,
  941.               tminpagestr, tminbytestr,(struct include *) NULL,
  942.               OFF, &tmaxreqs, &tmaxpages, &tmaxbytes, &tempint);
  943.     if (tsorthead -> name == NULL)
  944.       tq = OFF;
  945.     }
  946.  
  947.     if (Sq) {
  948.       Ssorthead = gensort(Shead, Shashsize, total_succ_reqs,
  949.               total_page_reqs, total_bytes, Ssortby, Sminreqstr,
  950.               Sminpagestr, Sminbytestr, (struct include *)NULL,
  951.               Ssortby == ALPHABETICAL, &Smaxreqs, &Smaxpages,
  952.               &Smaxbytes, &Smaxlength);
  953.       if (Ssorthead -> name == NULL)
  954.     Sq = OFF;
  955.     }
  956.  
  957.     if (oq) {
  958.       firstdom = domsort();
  959.       if (onumber == 0)
  960.     oq = OFF;
  961.       else
  962.     subdomsort();
  963.     }
  964.  
  965.   }    /* end else (there are things to report from the main logfile) */
  966.  
  967.   if (fq) {
  968.     /* aliasing referrers */
  969.     allaliases(fhead2, fhead, fhashsize, &tempint, &tempint, &tempint, 'f');
  970.     fsorthead = gensort(fhead, fhashsize, total_good_refs, total_ref_pages,
  971.             total_ref_bytes, fsortby, fminreqstr, fminpagestr,
  972.             fminbytestr, (struct include *)NULL, OFF, &fmaxreqs,
  973.             &fmaxpages, &fmaxbytes, &tempint);
  974.     if (fsorthead -> name == NULL)
  975.       fq = OFF;
  976.   }
  977.  
  978.   if (bq) {
  979.     bsorthead = gensort(bhead, bhashsize, total_good_brows,
  980.             total_brow_pages, total_brow_bytes, bsortby,
  981.             bminreqstr, bminpagestr, bminbytestr,
  982.             (struct include *)NULL, OFF, &bmaxreqs, &bmaxpages,
  983.             &bmaxbytes, &tempint);
  984.     if (bsorthead -> name == NULL)
  985.       bq = OFF;
  986.   } 
  987.  
  988.   if (Bq) {
  989.     Bsorthead = gensort(Bhead, Bhashsize, total_good_brows,
  990.             total_brow_pages, total_brow_bytes, Bsortby,
  991.             Bminreqstr, Bminpagestr, Bminbytestr,
  992.             (struct include *)NULL, OFF, &Bmaxreqs, &Bmaxpages,
  993.             &Bmaxbytes, &tempint);
  994.     if (Bsorthead -> name == NULL)
  995.       Bq = OFF;
  996.   }
  997.  
  998.   if (eq) {
  999.     errsort(errorder);
  1000.     if (errors[errorder[0]] < eminreqs)
  1001.       eq = OFF;
  1002.   }
  1003.  
  1004.   /*** Finally, do all the output ***/
  1005.  
  1006.   if (debug > 0) {
  1007.     fprintf(stderr, "S: successful requests: %d (%d)\n", total_succ_reqs,
  1008.         total_succ_reqs7);
  1009.     fprintf(stderr, "S: requests from cache: %d (%d)\n", cachereqs,
  1010.         cachereqs7);
  1011.     fprintf(stderr, "S: page requests from cache: %d (%d)\n", cachepages,
  1012.         cachepages7);
  1013.     fprintf(stderr, "S: failed requests: %d (%d)\n", total_fail_reqs,
  1014.         total_fail_reqs7);
  1015.     fprintf(stderr, "S: redirected requests: %d (%d)\n", total_other_reqs,
  1016.         total_other_reqs7);
  1017.     fprintf(stderr, "S: successful page requests: %d (%d)\n", total_page_reqs,
  1018.         total_page_reqs7);
  1019.     fprintf(stderr, "S: total bytes: %.0f (%.0f)\n", total_bytes,
  1020.         total_bytes7);
  1021.     fprintf(stderr, "S: corrupt lines: %d\n", corrupt_lines);
  1022.     fprintf(stderr, "S: unwanted lines: %d\n", other_lines);
  1023.     fprintf(stderr, "S: good referrer lines: %d\n", total_good_refs);
  1024.     fprintf(stderr, "S: bad referrer lines: %d\n", total_bad_refs);
  1025.     fprintf(stderr, "S: unwanted referrer lines: %d\n", total_masked_refs);
  1026.     fprintf(stderr, "S: referrer lines for pages: %d\n", total_ref_pages);
  1027.     fprintf(stderr, "S: total referrer bytes: %.0f\n", total_ref_bytes);
  1028.     fprintf(stderr, "S: good browser lines: %d\n", total_good_brows);
  1029.     fprintf(stderr, "S: bad browser lines: %d\n", total_bad_brows);
  1030.     fprintf(stderr, "S: unwanted browser lines: %d\n", total_masked_brows);
  1031.     fprintf(stderr, "S: browser lines for pages: %d\n", total_brow_pages); 
  1032.     fprintf(stderr, "S: total browser bytes: %.0f\n", total_brow_bytes);
  1033.     anywarns = ON;
  1034.  }
  1035.  
  1036.   output(rsorthead, isorthead, tsorthead, Ssorthead, firstdom, fsorthead,
  1037.      bsorthead, Bsorthead, errorder);
  1038.  
  1039. #ifdef MAC_EVENTS
  1040.   MacFini();
  1041. #endif
  1042.  
  1043.   return(OK);
  1044.    
  1045. }
  1046.